home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
sos3-2.lha
/
src
/
cci
/
cci.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-23
|
35KB
|
1,067 lines
/* --------------------------------------------------------------------------
* Copyright 1992 by Forschungszentrum Informatik (FZI)
*
* You can use and distribute this software under the terms of the licence
* you should have received along with this program.
* If not or if you want additional information, write to
* Forschungszentrum Informatik, "STONE", Haid-und-Neu-Strasse 10-14,
* D-7500 Karlsruhe 1, Germany.
* --------------------------------------------------------------------------
*/
// **************************************************************************
// Module cci 03/07/90 Juergen Uhl (ju)
// **************************************************************************
// implements methods of classes: cci_Schema_impl, cci_Method_impl
// **************************************************************************
// --------------------------------------------------------------------------
// Tracing conventions:
// no tracing: string conversions for external types
// cci_VL : symbol table patching
// cci_L : hash table management, lookup of file names for load
// cci_M : module initialization, local_... methods
// cci_H : other methods
// --------------------------------------------------------------------------
#include <sys/file.h>
#include <osfcn.h>
#include <libc.h>
#include <string.h>
#include <stream.h>
#include <sys/resource.h> // getrlimit, setrlimit
#include <sys/param.h> // MAXPATHLEN
#ifdef GNU
#include <unistd.h> // SEEK_SET
#define CAN_LOAD_INCREMENTALLY
#endif
#ifdef CAN_LOAD_INCREMENTALLY
extern "C" {
#include <a.out.h>
}
#if defined(MIPSEL) || defined(USG)
#ifndef hpux
#define exec aouthdr
#define a_text text_start
#define a_data data_start
#endif
#endif
#ifdef __pyr__
#define MUST_MPROTECT
#include <sys/mman.h>
extern "C" {
int mprotect (char *, int, int);
}
#endif
#endif CAN_LOAD_INCREMENTALLY
#include "sys.h"
#include "sos.h"
#include "smg.h"
#include "cci_err.h"
#include "trc_cci.h"
#include "cci_sos.h"
typedef void (*vfct_ptr_t)();
// --------------------------------------------------------------------------
#ifdef CAN_LOAD_INCREMENTALLY
LOCAL const char *ENVVAR_NAME = "SOSINCLOAD";
LOCAL class cci_FileNames
{ public:
char *executable, // name of running executable
*symtab_file, // name of temporary file containing symbol table of
// the executable as extended by previous loads
*tmpfile, // name of temporary file used to build the next
// version of symtab_file.
*stdlibs, // linker options to load standard libraries
*linker, // pathname of link editor
*crtmodule; // pathname of object module containing the
// startup routine for incrementally loaded code
sos_Bool echo; // flag: echo files to be loaded
cci_FileNames ();
~cci_FileNames ();
} cci_file_names;
cci_FileNames::cci_FileNames () {} // compiler error ??? destructor is only
// called, if construtor is defined
cci_FileNames::~cci_FileNames ()
{ if (symtab_file) unlink (symtab_file);
if (tmpfile) unlink (tmpfile);
}
#endif CAN_LOAD_INCREMENTALLY
// **************************************************************************
void cci_init (char** argv)
// **************************************************************************
{ T_PROC ("cci_init")
TT (cci_M, T_ENTER);
#ifndef CAN_LOAD_INCREMENTALLY
TT (cci_M, T_LEAVE);
#else
// argv[0] is expected to contain either the absolute pathname of
// the executable, or a relative pathname anchored at the current
// working directory.
if (*argv[0] EQ '/')
cci_file_names.executable = strdup (argv[0]);
else
{ char cwd[MAXPATHLEN];
smg_String tmp = smg_String(getwd(cwd)) + "/" + argv[0];
cci_file_names.executable = tmp.make_Cstring (SMG_TRANSFER);
}
sos_Bool do_default_init = TRUE;
char *settings = getenv (ENVVAR_NAME);
if (settings)
{ sos_Bool is_ok;
if (is_ok = (sos_Bool) (*settings EQ '+' OR *settings EQ '-'))
{ cci_file_names.echo = (sos_Bool)(*settings EQ '+');
while (*(++ settings) AND *settings EQ ' ')
;
if (*settings EQ EOS)
is_ok = FALSE;
else
{ for (char *start = settings;
*settings AND *settings != ' ';
++ settings)
;
int len = settings - start;
cci_file_names.linker = strncpy (new char[len+1], start, len);
cci_file_names.linker[len] = EOS;
while (*(++ settings) AND *settings EQ ' ')
;
if (*settings EQ EOS)
is_ok = FALSE;
else
{ for (start = settings;
*settings AND *settings != ' ';
++settings)
;
len = settings - start;
cci_file_names.crtmodule = strncpy (new char[len+1], start, len);
cci_file_names.crtmodule[len] = EOS;
cci_file_names.stdlibs = strdup (settings);
}
}
}
if (is_ok)
do_default_init = FALSE;
else
err_raise (err_USE, err_CCI_WRONG_INIT, getenv (ENVVAR_NAME), FALSE);
}
if (do_default_init)
{ cci_file_names.stdlibs = LIBSXX;
cci_file_names.linker = LDXX;
cci_file_names.crtmodule = CRTXX;
cci_file_names.echo = ECHOXX;
}
TT (cci_M, T_LEAVE; TXT("main"); TS(cci_file_names.executable);
TXT("ld"); TS(cci_file_names.linker);
TXT("crt"); TS(cci_file_names.crtmodule);
TXT("libs"); TS(cci_file_names.stdlibs);
TXT("echo"); TB(cci_file_names.echo));
#endif CAN_LOAD_INCREMENTALLY
}
// --------------------------------------------------------------------------
#if defined(CAN_LOAD_INCREMENTALLY) && defined(GNU)
/*
* The following is really nasty:
* We want to use the GNU startup module crt1+.o unchanged. Unfortunately:
* - this module must be slipped each time in front of the incrementally
* loaded object modules, but
* - contains an external symbol named '_initfn' which is initialized to a
* null pointer and called (resp. the referenced function) after the global
* constructors of the added code, and
* - we do not use this function pointer for the initialization of the
* loaded code.
* Hence, the second incremental load would fail due to multiple definitions
* of '_initfn'. Furthermore, we must initialize '_initfn' (it should point to
* a dummy function), but we can't write this initialization in this module
* since '_initfn' is not known before the incremental load.
* The `solution`:
* - Modify the temporary symbol table by making '_initfn' a filelocal symbol
* (the original symbol table of the executable remains unchanged).
* - This modification is done after each load.
* - Since we know the address of '_initfn' from the symbol table, we may
* as well use this knowledge to initialize _initfn.
*/
LOCAL void dummy_fct()
{ T_PROC ("cci: dummy_fct")
TT (cci_VL, T_ENTER);
TT (cci_VL, T_LEAVE);
}
LOCAL void patch_symboltable()
{ T_PROC ("cci: patch_symboltable")
TT (cci_VL, T_ENTER);
struct exec header;
int fd;
if ((fd = open (cci_file_names.symtab_file, O_RDWR, 0)) < 0)
err_raise (err_SYS, err_CCI_OPEN_FAILED, cci_file_names.symtab_file);
if (read (fd, (void*)&header, sizeof(header)) != sizeof(header))
err_raise (err_SYS, err_CCI_READ_FAILED, cci_file_names.symtab_file);
off_t sym_offset = N_SYMOFF(header),
stringbase = N_STROFF(header);
// Is there a better starting point to speed up the search (end of the
// former symboltable, maybe)?
// Current search times seem to be well below 5% of the overall load time.
char* searched = "__initfn";
int searchedlen = strlen (searched);
char readbuf[15];
readbuf[searchedlen] = '\0';
const int SYMBUF_SIZE = 1024 / sizeof(struct nlist);
struct nlist symbuf[SYMBUF_SIZE];
for (sos_Bool searching = TRUE; searching; )
{ if (lseek (fd, sym_offset, SEEK_SET) < 0)
err_raise (err_SYS, err_CCI_SEEK_FAILED, cci_file_names.symtab_file);
if (read (fd, (void*)&symbuf, sizeof(symbuf)) != sizeof(symbuf))
err_raise (err_SYS, err_CCI_READ_FAILED, cci_file_names.symtab_file);
struct nlist *sym_ptr = symbuf;
for (int idx = SYMBUF_SIZE; --idx >= 0; ++ sym_ptr)
{ if (sym_ptr->n_type == (N_DATA | N_EXT) && sym_ptr->n_un.n_strx > 0)
{ if (lseek(fd,(off_t)(stringbase+sym_ptr->n_un.n_strx),SEEK_SET) < 0)
err_raise (err_SYS, err_CCI_SEEK_FAILED,
cci_file_names.symtab_file);
if (read (fd, (void*)&readbuf, searchedlen) <= 0)
err_raise (err_SYS, err_CCI_READ_FAILED,
cci_file_names.symtab_file);
if (streql (readbuf, searched))
{ * (vfct_ptr_t*)sym_ptr->n_value = dummy_fct; // set _initfn
sym_ptr->n_type &= ~N_EXT; // clear external bit
if (lseek (fd, sym_offset, SEEK_SET) < 0)
err_raise (err_SYS, err_CCI_SEEK_FAILED,
cci_file_names.symtab_file);
if (write (fd, (void*)sym_ptr, sizeof(struct nlist))
< sizeof(struct nlist))
err_raise (err_SYS, err_CCI_WRITE_FAILED,
cci_file_names.symtab_file);
searching = FALSE;
break;
}
}
if ((sym_offset += sizeof(struct nlist)) >= stringbase)
err_raise (err_SYS, "symbol __initfn not found", NULL, FALSE);
} // for (... idx ...)
} // for (... searching ...)
close (fd);
TT (cci_VL, T_LEAVE);
}
#endif CAN_LOAD_INCREMENTALLY && GNU
// --------------------------------------------------------------------------
// conversions for external type cci_Fun
// --------------------------------------------------------------------------
sos_String make_string_from_cci_Fun_object (sos_Object f)
{ cci_Fun p1 = make_cci_Fun (f);
sos_String result
= smg_String ((sos_Int)p1, FALSE).make_String (TEMP_CONTAINER);
return result;
}
sos_Object make_cci_Fun_object_from_string (sos_String s)
{ sos_Cstring s1 = s.make_Cstring();
sos_Cstring ptr;
long l = strtol (s1, &ptr, 16);
delete s1;
sos_Object result = (ptr != s1 AND ptr[0] == 0)
? make_cci_Fun_object (cci_Fun (l))
: NO_OBJECT;
return result;
}
// --------------------------------------------------------------------------
// LOCAL: Management of loaded schema implementations
// (A schema is identified by its associated schema container.)
// --------------------------------------------------------------------------
#define CNT_HTAB_SIZE 128
struct cci_CntEntry {
cci_CntEntry *next;
sos_Container ct;
};
LOCAL cci_CntEntry *cnt_htab[CNT_HTAB_SIZE];
#ifdef CAN_LOAD_INCREMENTALLY
// The following array is used in 'lookup_files' to prevent from processing
// a schema (container) twice, and afterwards in 'cci_Schema_impl::load' to
// enter the newly loaded schemas (resp. their containers) into the hash table.
LOCAL struct {
sos_Container *array;
int size,
last_entry; } cnt_array = { NULL, 0, -1 };
// *************************************************************************
LOCAL sos_Bool enter_ct (sos_Container ct)
// *************************************************************************
{ T_PROC ("enter_ct")
TT (cci_L, T_ENTER);
for (int i = 0; i <= cnt_array.last_entry; ++ i)
if (ct EQ cnt_array.array[i])
{ TT (cci_L, T_LEAVE; TB(FALSE));
return FALSE;
}
if (++cnt_array.last_entry EQ cnt_array.size)
{ sos_Container *tmp;
if (cnt_array.size)
{ tmp = new sos_Container[cnt_array.size *= 2];
bcopy ((char*)cnt_array.array,
(char*)tmp,
cnt_array.last_entry * (int)sizeof(sos_Container));
delete cnt_array.array;
}
else
tmp = new sos_Container[cnt_array.size = 4];
cnt_array.array = tmp;
}
cnt_array.array[cnt_array.last_entry] = ct;
TT (cci_L, T_LEAVE; TB(TRUE));
return TRUE;
}
#endif CAN_LOAD_INCREMENTALLY
// *************************************************************************
LOCAL sos_Bool enter_schema (sos_Container ct, sos_Bool enter_if_new = TRUE)
// *************************************************************************
{ T_PROC ("enter_schema")
TT (cci_L, T_ENTER);
sos_Bool new_schema;
for (cci_CntEntry **e = &cnt_htab[ct % CNT_HTAB_SIZE];
*e AND (*e)->ct != ct;
e = &(*e)->next)
{}
if (*e)
new_schema = FALSE;
else
{ new_schema = TRUE;
if (enter_if_new)
{ *e = new cci_CntEntry;
(*e)->next = NULL;
(*e)->ct = ct;
}
}
TT (cci_L, T_LEAVE; TI((int)ct); TB(new_schema));
return new_schema;
}
// *************************************************************************
LOCAL void load_schema (sos_Container ct)
// *************************************************************************
{ T_PROC ("load_schema")
TT (cci_L, T_ENTER);
// This routine is the entry point to the incremental loading facility
// for the generated code, in particular via the C::make() calls.
for (cci_CntEntry **e = &cnt_htab[ct % CNT_HTAB_SIZE];
*e AND (*e)->ct != ct;
e = &(*e)->next)
{}
if (*e == NULL) // schema not yet loaded
{ sos_Bool found = FALSE;
sos_Schema_module sm = sos_Schema_module::retrieve (ct);
sos_Schema_impl_List sil = sm.get_impls();
if (sil != NO_OBJECT)
agg_iterate (sil, sos_Schema_impl si)
if (si.isa (cci_Schema_impl_type))
{ cci_Schema_impl::make (si).load();
found = TRUE;
break;
}
agg_iterate_end (sil, si);
if (NOT found)
err_raise (err_SYS, err_CCI_INC_LOAD_FAILED,
sm.get_name().make_Cstring());
}
TT (cci_L, T_LEAVE);
}
// *************************************************************************
LOCAL inline void schema_is_loaded (sos_Container ct)
// *************************************************************************
{ enter_schema (ct, TRUE);
}
#ifdef CAN_LOAD_INCREMENTALLY
// *************************************************************************
LOCAL void lookup_files (sos_Container ct,
sos_String_List objects,
sos_String_List libraries)
// *************************************************************************
{ T_PROC ("cci : lookup_files")
TT (cci_L, T_ENTER; TXT("container"); TI((int)ct));
sos_Schema_module sm = sos_Schema_module::retrieve (ct);
// first step: (recursively) add file names for imported schemas
// not yet loaded
sos_Imports impl = sm.get_imports();
if (impl != NO_OBJECT)
agg_iterate (impl, sos_Schema_module imp)
sos_Container imp_ct = imp.container();
if (enter_schema (imp_ct, FALSE) AND enter_ct (imp_ct))
lookup_files (imp_ct, objects, libraries);
agg_iterate_end (impl, imp);
cci_Schema_impl si = cci_Schema_impl::make (NO_OBJECT);
sos_Schema_impl_List sil = sm.get_impls();
if (sil != NO_OBJECT)
agg_iterate (sil, sos_Schema_impl i)
if (i.isa (cci_Schema_impl_type))
{ si = cci_Schema_impl::make (i);
break;
}
agg_iterate_end (sil, i);
if (si EQ NO_OBJECT)
err_raise (err_SYS, err_CCI_INC_LOAD_FAILED,
sm.get_name().make_Cstring());
// second step: (recursively) add file names for schemas this schema
// depends on and which are not yet loaded
sos_String_List sl = si.get_schemas();
if (sl != NO_OBJECT)
agg_iterate (sl, sos_String s)
sos_Schema_module sm = sos_Schema_module::lookup (s);
if (sm EQ NO_OBJECT)
err_raise (err_SYS, err_CCI_UNKNOWN_SCHEMA,
sm.get_name().make_Cstring());
sos_Container imp_ct = sm.container();
if (enter_schema (imp_ct, FALSE) AND enter_ct (imp_ct))
lookup_files (imp_ct, objects, libraries);
agg_iterate_end (sl, s);
// third step: process the direct dependencies of this schema on
// object modules, libraries
if ((sl = si.get_object_files()) != NO_OBJECT)
objects += sl;
if ((sl = si.get_libraries()) != NO_OBJECT)
libraries += sl;
TT (cci_L, T_LEAVE);
}
#endif CAN_LOAD_INCREMENTALLY
// --------------------------------------------------------------------------
// class cci_Schema_impl
// --------------------------------------------------------------------------
// *************************************************************************
cci_Schema_impl cci_Schema_impl::make_impl (sos_Schema_module s)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::make_impl")
TT (cci_H, T_ENTER);
cci_Schema_impl result;
sos_Bool found = FALSE;
sos_Schema_impl_List impls = s.get_impls();
if (impls == NO_OBJECT)
{ impls = sos_Schema_impl_List::create (s.container());
s.set_impls (impls);
}
else
agg_iterate (impls, sos_Schema_impl impl)
if (impl.isa (cci_Schema_impl_type))
{ found = TRUE;
result = cci_Schema_impl::make (impl);
break;
}
agg_iterate_end (impls, impl);
if (NOT found)
{ result = cci_Schema_impl::create (s.container());
impls.append (result);
}
TT (cci_H, T_LEAVE);
return result;
}
// **************************************************************************
void cci_Schema_impl::load ()
// **************************************************************************
{ T_PROC ("cci_Schema_impl::load")
TT (cci_H, T_ENTER);
if (NOT enter_schema (self.container(), FALSE))
{ TT (cci_H, T_LEAVE);
return;
}
#ifndef CAN_LOAD_INCREMENTALLY
err_raise (err_SYS, err_CCI_INC_LOAD_NOT_IMPL, NULL, FALSE);
sos_Offset o = self.offset(); // only to avoid AT&T compiler warnings!
#else
int fd;
struct exec header;
if (cci_file_names.executable EQ NULL)
err_raise (err_SYS, err_CCI_NOT_INITIALIZED, NULL, FALSE);
cnt_array.last_entry = -1;
enter_ct (self.container());
sos_String_List objects = sos_String_List::create (TEMP_CONTAINER, FALSE);
sos_String_List libs = sos_String_List::create (TEMP_CONTAINER, FALSE);
int hidden_objects = 1;
objects.append (smg_String(cci_file_names.crtmodule)
.make_String (TEMP_CONTAINER));
lookup_files (self.container(), objects, libs);
if (objects.card() EQ hidden_objects)
err_raise (err_SYS, err_CCI_INC_LOAD_FAILED, NULL, FALSE);
if (cci_file_names.symtab_file EQ NULL)
{ smg_String tmpfile = smg_String("") + sos_tempdir + "/sosdm.XXXXXX";
cci_file_names.symtab_file = tmpfile.make_Cstring (SMG_TRANSFER);
mktemp (cci_file_names.symtab_file);
tmpfile = smg_String("") + sos_tempdir + "/sosdf.XXXXXX";
cci_file_names.tmpfile = tmpfile.make_Cstring (SMG_TRANSFER);
mktemp (cci_file_names.tmpfile);
TT (cci_M, TXT("tmp.symtab"); TS(cci_file_names.symtab_file);
TXT("tmp.file"); TS(cci_file_names.tmpfile));
smg_String cmd = smg_String("ln -s ") + cci_file_names.executable + " "
+ cci_file_names.symtab_file;
if (system (cmd.make_Cstring (SMG_BORROW)))
err_raise (err_SYS, err_CCI_LINK_FAILED, NULL, FALSE);
}
unsigned size = 0;
smg_String cmd_head = smg_String("umask 111;")
+ cci_file_names.linker
+ " -N -A " + cci_file_names.symtab_file
+ " -T ";
smg_String cmd_tail = smg_String(" -o ") + cci_file_names.tmpfile;
agg_iterate (objects, sos_String on)
{ smg_String obj_module = on;
sos_Cstring obj_name = obj_module.make_Cstring (SMG_BORROW);
if ((fd = open (obj_name, O_RDONLY, 0)) < 0)
err_raise (err_SYS, err_CCI_OPEN_FAILED, obj_name);
if (read (fd, (void*) &header, sizeof (header)) != sizeof (header))
err_raise (err_SYS, err_CCI_READ_HEADER_FAILED, obj_name);
size += header.a_text + header.a_data + header.a_bss;
cmd_tail += smg_String(" ") + obj_module;
close (fd);
if (cci_file_names.echo AND --hidden_objects < 0)
cerr << "...loading " << obj_name << "\n";
}
agg_iterate_end (objects, on);
agg_iterate (libs, sos_String ln)
cmd_tail += smg_String(" ") + ln;
agg_iterate_end (libs, ln);
cmd_tail += smg_String(" ") + cci_file_names.stdlibs;
#ifdef EXEC_PAGESIZE
int pagsiz = EXEC_PAGESIZE;
#elif defined(PAGSIZ)
int pagsiz = PAGSIZ;
#else
int pagsiz = getpagesize();
#endif
if (size > 81920) // Add 8K in case of bigger files to increase the
size += 8192; // chance that the first size guess will suffice.
unsigned actual_size;// Repeat until size >= actual size.
char *obj_addr; // (The first guess might be to small because the
for (;;) // size of the BSS-Segment and the size of code
// loaded from libraries is not yet known.)
{ size += pagsiz - 1;
char *allocated = new char[size];
obj_addr = (char*)( ((unsigned)allocated + pagsiz - 1) & ~(pagsiz-1) );
size -= obj_addr - allocated;
// place additional object modules on page boundary
smg_String ldcmd = cmd_head + smg_String((sos_Int)obj_addr, FALSE)
+ cmd_tail;
TT (cci_M, TXT("load command"); TS(ldcmd.make_Cstring (SMG_BORROW)));
struct rlimit core_limit;
getrlimit (RLIMIT_CORE, &core_limit);
int cur_limit = core_limit.rlim_cur;
core_limit.rlim_cur = 0;
setrlimit (RLIMIT_CORE, &core_limit);
// suppress core file creation temporarily
int error_status = system (ldcmd.make_Cstring (SMG_BORROW));
core_limit.rlim_cur = cur_limit;
setrlimit (RLIMIT_CORE, &core_limit);
if (error_status)
{ unlink (cci_file_names.tmpfile);
err_raise (err_SYS, err_CCI_LOAD_FAILED, NULL, FALSE);
}
fd = open (cci_file_names.tmpfile, O_RDONLY, 0);
read (fd, (void*) &header, sizeof (header));
close (fd);
actual_size = header.a_text + header.a_data + header.a_bss;
if (actual_size <= size) break;
TT (cci_M, TXT("...repeat loading");
TXT("size guess"); TI(size);
TXT("actual size"); TI(actual_size));
delete allocated;
size = actual_size;
}
smg_String cmd = smg_String("rm ") + cci_file_names.symtab_file
+ ";mv " + cci_file_names.tmpfile
+ " " + cci_file_names.symtab_file;
if (system (cmd.make_Cstring (SMG_BORROW)))
err_raise (err_SYS, err_CCI_MOVE_FAILED, NULL, FALSE);
fd = open (cci_file_names.symtab_file, O_RDONLY, 0);
if (lseek (fd, (off_t)N_TXTOFF(header), SEEK_SET) < 0)
err_raise (err_SYS, err_CCI_SEEK_FAILED, NULL, FALSE);
if (read (fd, obj_addr, actual_size) != actual_size)
err_raise (err_SYS, err_CCI_READ_FAILED, NULL, FALSE);
close (fd);
#ifdef MUST_MPROTECT
if (mprotect (obj_addr, actual_size, PROT_READ|PROT_EXEC|PROT_WRITE))
err_raise (err_SYS, err_CCI_MKEXEC_FAILED, NULL, FALSE);
#endif MUST_MPROTECT
patch_symboltable();
(* (vfct_ptr_t)obj_addr)(); // call startup routine of crtmodule.
for (int i = 0; i <= cnt_array.last_entry; ++ i)
schema_is_loaded (cnt_array.array[i]);
#endif CAN_LOAD_INCREMENTALLY
TT (cci_H, T_LEAVE);
}
// *************************************************************************
void cci_Schema_impl::local_assign (cci_Schema_impl dest, sos_Object src_o)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::local_assign")
TT (cci_M, T_ENTER);
cci_Schema_impl src = cci_Schema_impl::make (src_o);
dest.get_object_files().assign (src.get_object_files());
dest.get_libraries().assign (src.get_libraries());
dest.get_schemas().assign (src.get_schemas());
TT (cci_M, T_LEAVE);
}
// *************************************************************************
void cci_Schema_impl::local_initialize (cci_Schema_impl impl)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::local_initialize")
TT (cci_M, T_ENTER);
sos_Container ct = impl.container();
impl.set_object_files (sos_String_List::create (ct, TRUE));
impl.set_libraries (sos_String_List::create (ct, TRUE));
impl.set_schemas (sos_String_List::create (ct, TRUE));
TT (cci_M, T_LEAVE);
}
// *************************************************************************
void cci_Schema_impl::local_finalize (cci_Schema_impl impl)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::local_finalize")
TT (cci_M, T_ENTER);
impl.get_object_files().destroy();
impl.get_libraries().destroy();
impl.get_schemas().destroy();
TT (cci_M, T_LEAVE);
}
// --------------------------------------------------------------------------
// class cci_Schema_impl : Management of dynamic type representation objects
// --------------------------------------------------------------------------
#define MAKE_OBJ_HTAB_SIZE 1024
struct cci_MakeObjEntry {
cci_MakeObjEntry *next;
sos_Id f, t;
cci_Make_obj obj;
};
LOCAL cci_MakeObjEntry *make_obj_htab[MAKE_OBJ_HTAB_SIZE];
// *************************************************************************
cci_Make_obj cci_Schema_impl::get_make_obj (sos_Id t, sos_Id f)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::get_make_obj")
TT (cci_L, T_ENTER);
if (f.offset() == 0 AND (sos_Int)f.container() == 0) // type of NO_OBJECT
f = t;
int hash = (f.offset() ^ (sos_Int) f.container()
^ ((t.offset() ^ (sos_Int) t.container()) >> 4))
% MAKE_OBJ_HTAB_SIZE;
cci_Make_obj result;
for (sos_Bool first_lookup = TRUE; ; first_lookup = FALSE)
{ for (cci_MakeObjEntry **e = &make_obj_htab[hash];
*e AND ((*e)->f != f OR (*e)->t != t);
e = &(*e)->next)
{}
if (*e)
{ result = (*e)->obj;
break;
}
else if (first_lookup)
#if BOOT
err_raise (err_SYS, err_CCI_INVALID_MAKE,
"cci_Schema_impl::get_make_obj", FALSE);
#else
load_schema (f.container());
#endif
else
{
sos_Type tp = sos_Type::make (sos_Typed_id::make (f));
sos_Type rt = tp.root();
#ifdef ATT
if (tp.operator!=(rt))
#else
if (tp != rt)
#endif
result = cci_Schema_impl::get_make_obj (t, rt.typed_id().get_id());
else
err_raise (err_SYS, err_CCI_INVALID_MAKE,
"cci_Schema_impl::get_make_obj", FALSE);
break;
}
}
TT (cci_L, T_LEAVE);
return result;
}
// *************************************************************************
void cci_Schema_impl::enter_make_obj (sos_Id t, sos_Id f, cci_Make_obj obj)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::enter_make_obj")
TT (cci_L, T_ENTER);
schema_is_loaded (f.container());
int hash = (f.offset() ^ (sos_Int) f.container()
^ ((t.offset() ^ (sos_Int) t.container()) >> 4))
% MAKE_OBJ_HTAB_SIZE;
for (cci_MakeObjEntry **e = &make_obj_htab[hash];
*e AND ((*e)->f != f OR (*e)->t != t);
e = &((*e)->next))
{}
if (! *e)
{ *e = new cci_MakeObjEntry;
(*e)->next = NULL;
(*e)->f = f;
(*e)->t = t;
(*e)->obj = obj;
}
TT (cci_L, T_LEAVE);
}
// --------------------------------------------------------------------------
// class cci_Schema_impl : C++ method implementation management
// --------------------------------------------------------------------------
#define FUN_HTAB_SIZE 1024
struct cci_Fun_entry {
cci_Fun_entry* next;
sos_Id m;
cci_Fun fun;
};
LOCAL cci_Fun_entry *fun_htab[FUN_HTAB_SIZE];
// *************************************************************************
cci_Fun cci_Schema_impl::get_fun (sos_Id m)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::get_fun")
TT (cci_L, T_ENTER);
load_schema (m.container());
int hash = (m.offset() ^ (sos_Int) m.container()) % FUN_HTAB_SIZE;
for (cci_Fun_entry **e = &fun_htab[hash];
*e AND (*e)->m != m;
e = &(*e)->next)
{}
cci_Fun fun;
if (*e)
fun = (*e)->fun;
else
err_raise (err_SYS, err_CCI_INVALID_METHOD,
"cci_Schema_impl::get_fun", FALSE);
TT (cci_L, T_LEAVE);
return fun;
}
// *************************************************************************
void cci_Schema_impl::enter_fun (sos_Id m, cci_Fun fun)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::enter_fun")
TT (cci_L, T_ENTER);
int hash = (m.offset() ^ (sos_Int) m.container()) % FUN_HTAB_SIZE;
for (cci_Fun_entry **e = &fun_htab[hash];
*e AND NOT ((*e)->m == m);
e = &((*e)->next))
{}
if (! *e)
{ *e = new cci_Fun_entry;
(*e)->next = NULL;
(*e)->m = m;
(*e)->fun = fun;
}
TT (cci_L, T_LEAVE);
}
// *************************************************************************
void cci_Schema_impl::enter_string_io (sos_Id et,
cci_IO_fun from_extern,
cci_IO_fun to_extern)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::enter_string_io")
TT (cci_L, T_ENTER);
sos_Id et1 = sos_Id::make (et.container(), et.offset() + 1);
cci_Schema_impl::enter_fun (et , (cci_Fun)from_extern);
cci_Schema_impl::enter_fun (et1, (cci_Fun)to_extern);
TT (cci_L, T_LEAVE);
}
// --------------------------------------------------------------------------
// class cci_Schema_impl : generic conversions for external types
// --------------------------------------------------------------------------
typedef sos_Object (*cci_cnv_from_string)(sos_String);
typedef sos_String (*cci_cnv_to_string)(sos_Object);
// *************************************************************************
sos_Object cci_Schema_impl::extern_object_from_string (sos_Type tp,
sos_String s)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::extern_object_from_string")
TT (cci_H, T_ENTER);
sos_Id id = tp.typed_id().get_id();
sos_Id id1 = sos_Id::make (id.container(), id.offset() + 1);
sos_Object result
= (* (cci_cnv_from_string)(cci_Schema_impl::get_fun (id1)) ) (s);
TT (cci_H, T_LEAVE);
return result;
}
// *************************************************************************
sos_String cci_Schema_impl::string_from_extern_object (sos_Object o)
// *************************************************************************
{ T_PROC ("cci_Schema_impl::string_from_extern_object")
TT (cci_H, T_ENTER);
sos_Id id = o.typed_id().get_tp();
sos_String result
= (* (cci_cnv_to_string)(cci_Schema_impl::get_fun (id)) ) (o);
TT (cci_H, T_LEAVE);
return result;
}
// --------------------------------------------------------------------------
// class cci_Method_impl
// --------------------------------------------------------------------------
// *************************************************************************
cci_Method_impl cci_Method_impl::make_impl (sos_Method m)
// *************************************************************************
{ T_PROC ("cci_Method_impl::make_impl")
TT (cci_H, T_ENTER);
cci_Method_impl result;
sos_Bool found = FALSE;
sos_Method_impl_List impls = m.get_impls();
if (impls == NO_OBJECT)
{ impls = sos_Method_impl_List::create (m.container());
m.set_impls (impls);
}
else
{ agg_iterate (impls, sos_Method_impl impl)
if (impl.isa (cci_Method_impl_type))
{ found = TRUE;
result = cci_Method_impl::make (impl);
break;
}
agg_iterate_end (impls, impl);
}
if (NOT found)
{ result = cci_Method_impl::create (m.container());
impls.append (result);
}
TT (cci_H, T_LEAVE);
return result;
}
// *************************************************************************
void cci_Method_impl::enter_fun (cci_Fun fun)
// *************************************************************************
{ T_PROC ("cci_Method_impl::enter_fun")
TT (cci_L, T_ENTER);
cci_Schema_impl::enter_fun (self.typed_id().get_id(), fun);
TT (cci_L, T_LEAVE);
}
// *************************************************************************
sos_Object cci_Method_impl::execute (sos_Object o, sos_Object_Array p)
// *************************************************************************
{ T_PROC ("cci_Method_impl::execute")
TT (cci_H, T_ENTER);
sos_Object result;
cci_Fun f = cci_Schema_impl::get_fun (self.typed_id().get_id());
result = (*f) (o, p);
TT (cci_H, T_LEAVE);
return result;
}
// *************************************************************************
sos_String cci_Method_impl::operator_string (sos_String op_name)
// *************************************************************************
{ T_PROC ("cci_Method_impl::operator_string")
TT (cci_H, T_ENTER);
smg_String op_string = op_name;
smg_String result_string;
sos_String result;
if (op_string.equal ("+") ) result_string = "__plus";
else if (op_string.equal ("-") ) result_string = "__minus";
else if (op_string.equal ("*") ) result_string = "__times";
else if (op_string.equal ("/") ) result_string = "__div";
else if (op_string.equal ("%") ) result_string = "__rem";
else if (op_string.equal ("^") ) result_string = "__xor";
else if (op_string.equal ("&") ) result_string = "__and";
else if (op_string.equal ("|") ) result_string = "__or";
else if (op_string.equal ("~") ) result_string = "__not";
else if (op_string.equal ("!") ) result_string = "__logical_not";
else if (op_string.equal ("=") ) result_string = "__assign";
else if (op_string.equal ("<") ) result_string = "__less";
else if (op_string.equal (">") ) result_string = "__greater";
else if (op_string.equal ("+=") ) result_string = "__plus_assign";
else if (op_string.equal ("-=") ) result_string = "__minus_assign";
else if (op_string.equal ("*=") ) result_string = "__times_assign";
else if (op_string.equal ("/=") ) result_string = "__div_assign";
else if (op_string.equal ("%=") ) result_string = "__rem_assign";
else if (op_string.equal ("^=") ) result_string = "__xor_assign";
else if (op_string.equal ("&=") ) result_string = "__and_assign";
else if (op_string.equal ("|=") ) result_string = "__or_assign";
else if (op_string.equal ("<<") ) result_string = "__shift_left";
else if (op_string.equal (">>") ) result_string = "__shift_right";
else if (op_string.equal (">>=")) result_string = "__shift_right_assign";
else if (op_string.equal ("<<=")) result_string = "__shift_left_assign";
else if (op_string.equal ("==") ) result_string = "__equal";
else if (op_string.equal ("!=") ) result_string = "__not_equal";
else if (op_string.equal ("<=") ) result_string = "__less_equal";
else if (op_string.equal (">=") ) result_string = "__greater_equal";
else if (op_string.equal ("&&") ) result_string = "__logical_and";
else if (op_string.equal ("||") ) result_string = "__logical_or";
else if (op_string.equal ("++") ) result_string = "__increment";
else if (op_string.equal ("--") ) result_string = "__decrement";
else if (op_string.equal (",") ) result_string = "__comma";
else if (op_string.equal ("->*")) result_string = "__member_access";
else if (op_string.equal ("->") ) result_string = "__access";
else if (op_string.equal ("()") ) result_string = "__function";
else if (op_string.equal ("[]") ) result_string = "__index";
else result_string = op_string;
result = result_string.make_String (TEMP_CONTAINER);
TT (cci_H, T_LEAVE);
return result;
}